`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/30 16:05:06
// Design Name: 
// Module Name: multiply
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module multiply #(
    parameter N = 4,
    parameter M = 4
) (
    input clk,
    input rstn,  // 是否重置 0重置，1恢复
    input [N-1:0] multn,  // 被乘数
    input [M-1:0] multm,  // 乘数
    output finish,  // 是否完成计算结果
    output [N+M-1:0] out  //计算结果
);

  reg [N+M-1:0] mult_res;  // 累加结果
  integer mult_index;  // 当前累加次数

  initial begin
    mult_res   = 0;
    mult_index = 0;
  end

  always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
      mult_index <= 0;
    end
    else if (mult_index < M) begin // 未到当前乘数位数并且当前乘数所在位值为1就继续累加
      mult_index <= mult_index + 1;
    end
    // else begin
    //   mult_index <= 0;  // 计算结果完成之后重新设置为0 这里先注释掉 不然就一直循环计算了
    // end

  end

  // 计算结果并累加
  always @(posedge clk or negedge rstn) begin
    if (!rstn) begin
      mult_res <= 0;
    end
    else if (mult_index == 0) begin // 未到当前乘数位数并且当前乘数所在位值为1就继续累加
      mult_res <= multm[mult_index] ? ({{(M) {1'b0}}, multn} << mult_index): 0;  // 补充位数并左移
    end
    else if (mult_index < M) begin // 未到当前乘数位数并且当前乘数所在位值为1就继续累加
      mult_res <= multm[mult_index] ? mult_res + ({{(M) {1'b0}}, multn} << mult_index): mult_res;  // 补充位数并左移
    end
    // else if (mult_index == M) begin // 乘好了之后就重新设置为0 这里先注释掉 不然就一直循环计算了
    //   mult_res <= 0;
    // end
  end

  reg [N + M-1:0] out_data;
  reg out_en;

  // 计算输出值
  always @(negedge clk or negedge rstn) begin
    if (!rstn) begin
      out_data <= 0;
      out_en   <= 0;
    end else if (mult_index == M) begin
      out_data <= mult_res;
      out_en   <= 1;
    end else begin
      out_data <= 0;
      out_en   <= 0;
    end
  end
  assign finish = out_en;  // 链接输出端口
  assign out = out_data;  // 链接输出端口

endmodule
